import json
from databaseObj import Database
import common

class DeployedContractRecord:
    def __init__(
        self,
        account_address,
        contract_address,
        contract_abi,
        contract_src,
        is_DO_contract
    ):
        self.account_address = account_address
        self.contract_address = contract_address
        self.contract_abi = contract_abi 
        self.contract_src = contract_src 
        self.is_DO_contract = is_DO_contract

class ABEOwnerKeyRecord:
    def __init__(
        self,
        account_address,
        master_key,
        public_key,
    ):
        self.acct_addr = account_address
        self.master_key = master_key
        self.public_key = public_key

class ABEUserKeyRecord:
    def __init__(
        self,
        master_acct_addr,
        user_acct_addr,
        private_key,
        public_key
    ):
        self.user_acct_addr = user_acct_addr
        self.master_acct_addr = master_acct_addr
        self.private_key = private_key
        self.public_key = public_key

class AESKeyRecord:
    def __init__(
        self,
        this_side_acct_addr,
        the_other_side_acct_addr,
        the_key
    ):
        self.this_side_acct_addr = this_side_acct_addr,
        self.the_other_side_acct_addr = the_other_side_acct_addr
        self.the_key = the_key

class SharedKeyRecord:
    def __init__(
        self,
        this_side_acct_addr,
        the_other_side_acct_addr,
        the_key
    ):
        self.this_side_acct_addr = this_side_acct_addr,
        self.the_other_side_acct_addr = the_other_side_acct_addr
        self.the_key = the_key

class DBHelper:
    _db = Database(common.args.DBPath,check_same_thread=False)
    _DeployedContract = "DeployedContract"
    _ABEOwnerKey = "ABEOwnerKey"
    _ABEUserKey = "ABEUserKey"
    _AESKey = "AESKey"
    _SharedKey = "SharedKey"

    @classmethod
    def execute(cls,str_ls,args):
        if isinstance(str_ls,str):
            str_ls = [str_ls]
        cls._db.execute(common.strtools.merge_lines(*str_ls),args)

    @classmethod
    def commit(cls):
        cls._db.commit()

    @classmethod
    def fetch_one(cls):
        return cls._db.fetchone()

    @classmethod 
    def fetch_all(cls):
        return cls._db.fetchall()

    @classmethod
    def get_all_DO_contracts(cls):
        cls.execute(
            [
                "select",
                "{},{},{},{},{}".format(
                    "account_address",
                    "contract_address",
                    "contract_abi",
                    "contract_src",
                    "is_DO_contract"
                ),
                "from {} where is_DO_contract=?".format(cls._DeployedContract)
            ],
            [True]
        )
        records = cls.fetch_all()
        assert len(records), "没有找到记录"
        return [DeployedContractRecord(
            account_address = record[0],
            contract_address = record[1],
            contract_abi = record[2],
            contract_src = record[3],
            is_DO_contract = bool(record[4])
        ) for record in records]
        

    @classmethod
    def get_contract(cls,contract_address):
        cls.execute(
            [
                "select",
                "{},{},{},{},{}".format(
                    "account_address",
                    "contract_address",
                    "contract_abi",
                    "contract_src",
                    "is_DO_contract"
                ),
                "from {} where contract_address=?".format(cls._DeployedContract)
            ],
            [contract_address]
        )
        record = cls.fetch_one()
        assert record is not None, "没有找到该记录"
        return DeployedContractRecord(
            account_address = record[0],
            contract_address = record[1],
            contract_abi = record[2],
            contract_src = record[3],
            is_DO_contract = bool(record[4])
        )

    @classmethod
    def get_contract_with_acct_addr(cls,account_address,is_DO_contract:bool):
        cls.execute(
            [
                "select",
                "{},{},{},{},{}".format(
                    "account_address",
                    "contract_address",
                    "contract_abi",
                    "contract_src",
                    "is_DO_contract"
                ),
                "from {} where".format(cls._DeployedContract),
                "account_address=? and is_DO_contract=?"
            ],
            [
                account_address,
                is_DO_contract
            ]
        )
        record = cls.fetch_one()
        assert record is not None, "没有找到该记录"
        return DeployedContractRecord(
            account_address = record[0],
            contract_address = record[1],
            contract_abi = record[2],
            contract_src = record[3],
            is_DO_contract = bool(record[4])
        )

    @classmethod 
    def get_ABEOwnerKey(cls,account_address):
        cls.execute(
            [
                "select",
                "{},{},{}".format(
                    "account_address",
                    "master_key",
                    "public_key"
                ),
                "from {} where account_address=?".format(cls._ABEOwnerKey)
            ],
            [account_address]
        )
        record = cls.fetch_one()
        assert record is not None, "没有找到该记录"
        return ABEOwnerKeyRecord(
            account_address = record[0],
            master_key = record[1],
            public_key = record[2]
        )

    @classmethod 
    def get_ABEUserKey(cls,master_acct_addr,user_acct_addr):
        cls.execute(
            [
                "select",
                "{},{},{},{}".format(
                    "master_account_address",
                    "user_account_address",
                    "private_key",
                    "public_key"
                ),
                "from {} where".format(cls._ABEUserKey),
                "master_account_address=? and user_account_address=?"
            ],
            [
                master_acct_addr,
                user_acct_addr
            ]
        )
        record = cls.fetch_one()
        assert record is not None, "没有找到该记录"
        return ABEUserKeyRecord(
            master_acct_addr = record[0],
            user_acct_addr = record[1],
            private_key = record[2],
            public_key = record[3]
        )

    @classmethod 
    def get_AESKey(
        cls,
        this_side_acct_addr,
        the_other_side_acct_addr
    ):
        cls.execute(
            [
                "select",
                "{},{},{}".format(
                    "this_side_account_address",
                    "the_other_side_account_address",
                    "the_key"
                ),
                "from {} where".format(cls._AESKey),
                "this_side_account_address=?",
                "and",
                "the_other_side_account_address=?"
            ],
            [
                this_side_acct_addr,
                the_other_side_acct_addr
            ]
        )
        record = cls.fetch_one()
        assert record is not None, "没有找到该记录"
        return AESKeyRecord(
            this_side_acct_addr = record[0],
            the_other_side_acct_addr = record[1],
            the_key = record[2]
        )

    @classmethod 
    def get_SharedKey(
        cls,
        this_side_acct_addr,
        the_other_side_acct_addr
    ):
        cls.execute(
            [
                "select",
                "{},{},{}".format(
                    "this_side_account_address",
                    "the_other_side_account_address",
                    "the_key"
                ),
                "from {} where".format(cls._SharedKey),
                "this_side_account_address=?",
                "and",
                "the_other_side_account_address=?"
            ],
            [
                this_side_acct_addr,
                the_other_side_acct_addr
            ]
        )
        record = cls.fetch_one()
        assert record is not None, "没有找到该记录"
        return SharedKeyRecord(
            this_side_acct_addr = record[0],
            the_other_side_acct_addr = record[1],
            the_key = record[2]
        )
        

    @classmethod
    def save_contract(
        cls,
        owner_acct_address,
        contract_address,
        contract_abi,
        contract_src,
        is_DO_contract:bool
    ):
        """先删后插其实很不好，会生成多余的日志（但这里就将就用了。。。）
        """
        cls.execute(
            "delete from {} where contract_address=?".format(cls._DeployedContract),
            [contract_address]
        )
        cls.execute(
            [
                "insert into",
                "{}({},{},{},{},{})".format(
                    cls._DeployedContract,
                    "contract_address",
                    "account_address",
                    "contract_abi",
                    "contract_src",
                    "is_DO_contract"
                ),
                "values (?,?,?,?,?)"
            ],
            (
                contract_address,
                owner_acct_address,
                contract_abi,
                contract_src,
                bool(is_DO_contract)
            )
        )
        cls.commit()
        return True

    @classmethod 
    def save_ABEOwnerKey(
        cls,
        account_address,
        master_key,
        public_key
    ):
        cls.execute(
            "delete from {} where account_address=?".format(cls._ABEOwnerKey),
            [account_address]
        )
        cls.execute(
            [
                "insert into",
                "{}({},{},{})".format(
                    cls._ABEOwnerKey,
                    "account_address",
                    "master_key",
                    "public_key"
                ),
                "values (?,?,?)"
            ],
            (
                account_address,
                master_key,
                public_key
            )
        )
        cls.commit()
        return True
    
    @classmethod
    def save_ABEUserKey(
        cls,
        user_acct_addr,
        master_acct_addr,
        private_key,
        public_key
    ):
        _m = "master_account_address"
        _u = "user_account_address"
        cls.execute(
            "delete from {} where {}=? and {}=?".format(
                cls._ABEUserKey,_m,_u
            ),
            [master_acct_addr,user_acct_addr]
        )
        cls.execute(
            [
                "insert into",
                "{}({},{},{},{})".format(
                    cls._ABEUserKey,
                    _m,
                    _u,
                    "private_key",
                    "public_key"
                ),
                "values (?,?,?,?)"
            ],
            (
                master_acct_addr,
                user_acct_addr,
                private_key,
                public_key
            )
        )
        cls.commit()
        return True

    @classmethod 
    def save_AESKey(
        cls,
        this_side_acct_addr,
        the_other_side_acct_addr,
        the_key
    ):
        _here = "this_side_account_address"
        _there = "the_other_side_account_address"
        cls.execute(
            "delete from {} where {}=? and {}=?".format(
                cls._AESKey,
                _here,
                _there
            ),
            [
                this_side_acct_addr,
                the_other_side_acct_addr
            ]
        )
        cls.execute(
            [
                "insert into",
                "{}({},{},{})".format(
                    cls._AESKey,
                    _here,
                    _there,
                    "the_key"
                ),
                "values (?,?,?)"
            ],
            [
                this_side_acct_addr,
                the_other_side_acct_addr,
                the_key
            ]
        )
        cls.commit()
        return True

    @classmethod 
    def save_SharedKey(
        cls,
        this_side_acct_addr,
        the_other_side_acct_addr,
        the_key
    ):
        _here = "this_side_account_address"
        _there = "the_other_side_account_address"
        cls.execute(
            "delete from {} where {}=? and {}=?".format(
                cls._SharedKey,
                _here,
                _there
            ),
            [
                this_side_acct_addr,
                the_other_side_acct_addr
            ]
        )
        cls.execute(
            [
                "insert into",
                "{}({},{},{})".format(
                    cls._SharedKey,
                    _here,
                    _there,
                    "the_key"
                ),
                "values (?,?,?)"
            ],
            [
                this_side_acct_addr,
                the_other_side_acct_addr,
                the_key
            ]
        )
        cls.commit()
        return True



# if __name__=="__main__":
#     print(DBHelper.get_all_DO_contracts())